﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Z1029.NoteEditor
{
    public class Note : MonoBehaviour, IComparable<Note>,IEditable<Note>
    {
        public NoteGlobalView.Note targetNote;
        public bool isEditing;

        public NoteType type;
        public Direction direction;
        public NoteData noteData;
        public int noteSoundID;
        public BoxCollider box;

        [Tooltip("HL Sprite")]
        public Sprite HighLight;
        public Sprite[] notes;
        public SpriteRenderer thisRenderer;
        public JudgementLine judgeline;

        public virtual void Awake()
        {
            thisRenderer = GetComponent<SpriteRenderer>();
        }

        public virtual void OnNoteStart()
        {
        }

        public virtual void Start()
        {
            //isRegistered = false;
            judgeline = transform.parent.GetComponent<JudgementLine>();
            noteData.time = Utils.GetTimeFromBeatTime(noteData.beatTime, judgeline.bpm);
            noteData.holdTime = Utils.GetTimeFromBeatTime(noteData.beatHoldTime, judgeline.bpm);
            thisRenderer.color = Color.white;
            transform.localScale = new Vector3(LevelController.noteSize, LevelController.noteSize, 1f);
            transform.localEulerAngles = Vector3.zero;
            OnNoteStart();
            transform.localPosition = new Vector3(noteData.positionX, 0, 0);
            SetNotePosition();
        }

        public void SetNoteHighLight()
        {
            if (HLNote(noteData.beatTime))
            {
                thisRenderer.sprite = HighLight;
            }
        }

        public virtual float CalculateNotePosY()
        {
            float num = CalculateDistance();
            if (direction == Direction.Below)
            {
                num = -num;
            }
            float realY = transform.localPosition.y + (num - transform.localPosition.y);
            return realY;
        }

        public virtual float CalculateDistance()
        {
            return (float)(1 * judgeline.GetSpeedDistance(noteData.time));
        }

        public virtual void SetNotePosition()
        {
            transform.localPosition = new Vector3(noteData.positionX, CalculateNotePosY(), 0f);
        }
        public virtual void Update()
        {
            type = noteData.type;
            noteData.time = Utils.GetTimeFromBeatTime(noteData.beatTime, judgeline.bpm);
            noteData.holdTime = Utils.GetTimeFromBeatTime(noteData.beatHoldTime, judgeline.bpm);
            thisRenderer.sprite = notes[(int)noteData.type];
            //noteData.positionX = transform.localPosition.x;
            if (noteData.type != NoteType.Hold)
            {
                SetNotePosition();
                UpdateTargetNoteData();

                transform.localScale = new Vector3(LevelController.noteSize, LevelController.noteSize, 1f);
                transform.localEulerAngles = Vector3.zero;
                if (LevelController.nowTime > noteData.time)
                {
                    thisRenderer.enabled = false;
                    box.enabled = false;
                }
                else
                {
                    thisRenderer.enabled = true;
                    box.enabled = true;
                }
                transform.localScale = new Vector3(LevelController.noteSize, LevelController.noteSize, LevelController.noteSize);
            }
            else
            {
                UpdateHoldSize();
                SetDirection();
                SetHoldPosition();
                if (LevelController.nowTime > noteData.time + noteData.holdTime)
                {
                    thisRenderer.enabled = false;
                    box.enabled = false;
                }
                else
                {
                    thisRenderer.enabled = true;
                    box.enabled = true;
                }

            }
            ///Auto
            //if (LevelController.nowTime > noteData.time) OnHit(HitACC.Perfect);
        }

        public void UpdateTargetNoteData()
        {
            targetNote.type = (NoteGlobalView.NoteType)noteData.type;
            targetNote.direction = (NoteGlobalView.Note.Direction)direction;
            NoteGlobalView.Note.NoteData data = new NoteGlobalView.Note.NoteData
            {
                speed = noteData.speed,
                positionX = noteData.positionX,
                beatHoldTime = noteData.beatHoldTime,
                holdTime = noteData.holdTime,
                beatTime = noteData.beatTime,
                type = (NoteGlobalView.NoteType)noteData.type
            };
            targetNote.noteData = data;
        }

        public void UpdateHoldSize()
        {
            float sizeY;
            //judgeline = transform.parent.GetComponent<JudgementLine>();
            noteData.time = Utils.GetTimeFromBeatTime(noteData.beatTime, judgeline.bpm);
            noteData.holdTime = Utils.GetTimeFromBeatTime(noteData.beatHoldTime, judgeline.bpm);
            //sizeY = (float)noteData.holdTime * speed; 
            sizeY = Mathf.Abs((float)(judgeline.GetSpeedDistance(noteData.time + noteData.holdTime) - judgeline.GetSpeedDistance(noteData.time)) );
            if (judgeline.GetSpeedDistance(noteData.time) <= 0)
            {
                sizeY = Mathf.Abs((float)judgeline.GetSpeedDistance(noteData.time + noteData.holdTime)) ;
                //sizeY = sizeY-sizeY*(float)((LevelController.nowTime - noteData.time) / noteData.holdTime);//sizeY = (float)(judgeline.GetSpeedDistance(noteData.time + noteData.holdTime) * speed);
            }
            //if (sizeY != 0) holdHead.transform.localScale = new Vector3(1, 3 / sizeY, 1);
            sizeY /= 19f;
            transform.localScale = new Vector3(LevelController.noteSize, sizeY, 1f);
        }

        public void SetDirection()
        {
            if (direction == Direction.Below)
            {
                Vector3 localEulerAngles = new Vector3(0f, 0f, -180f);
                transform.localEulerAngles = localEulerAngles;
            }
        }
        public void SetHoldPosition()
        {
            if (judgeline.GetSpeedDistance(noteData.time) > 0) transform.localPosition = new Vector3(noteData.positionX, CalculateNotePosY(), 0f);
            else transform.localPosition = new Vector3(noteData.positionX, 0, 0f);
            //if (judgeline.GetSpeedDistance(noteData.time) > 0) transform.localPosition = new Vector3(noteData.positionX, (float)(noteData.time-LevelController.nowTime)*noteData.speed, 0f);
        }

        public static bool HLNote(int beatTime)
        {
            int count = 0;
            for (int i = 0; i < LevelController.instance.notes.Length; i++)
            {
                if (LevelController.instance.notes[i].noteData.beatTime == beatTime)
                {
                    count++;
                }
            }
            return count >= 2;
        }

        void OnDestroy()
        {
            if(NoteGlobalView.JudgementLine.IsEditing)Destroy(targetNote.gameObject);
        }

        public int CompareTo(Note other)
        {
            if (noteData.time > other.noteData.time)
            {
                return 1;
            }
            else if (noteData.time < other.noteData.time)
            {
                return -1;
            }
            else return 0;
            //throw new NotImplementedException();
        }

        public T GetData<T>()
        {
            throw new NotImplementedException();
        }

        public void SetData<T>()
        {
            throw new NotImplementedException();
        }

        public void UpdateData()
        {
            throw new NotImplementedException();
        }

        [Serializable]
        public struct NoteData
        {
            public NoteType type;
            public double time;
            public float positionX;
            public float speed;
            public double holdTime;
            public int beatTime;
            public int beatHoldTime;
            public int index;
        }
        public enum Direction
        {
            Above, Below
        }
        public enum HitACC
        {
            Perfect, Good, Bad, Miss
        }
    }

    public enum NoteType
    {
        Click, Drag, Hold, Flick
    }
}

